package cn.dansj.common.utils.json;

import cn.dansj.common.utils.reflect.ClassUtils;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.core.util.Separators;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.cfg.ConstructorDetector;
import com.fasterxml.jackson.databind.cfg.EnumFeature;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

class ObjectMapperFactory {
    private static final JSONMapper mapper = new JSONMapper();
    private static final Logger logger = LoggerFactory.getLogger(ObjectMapperFactory.class);
    private static final ConcurrentHashMap<EnumSet<Feature>, WeakReference<JSONMapper>> cache = new ConcurrentHashMap<>();
    private static final long CLEANUP_INTERVAL = TimeUnit.HOURS.toMillis(1);
    private static volatile long lastCleanupTime = System.currentTimeMillis();
    private static final boolean hasGSONClass = ClassUtils.isPresent("com.google.gson.annotations.SerializedName");

    static {
        configMapper();
    }

    private static void configMapper() {
        // 序列化配置
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 不序列化null字段
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); // 空对象不报错
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); // 日期不写为时间戳
        // 反序列化配置
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 忽略未知属性
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); // 允许单引号
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); // 允许未加引号的字段名
        mapper.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);
        mapper.configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, false); //不允许反序列化final字段
        // 日期格式化
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        mapper.setTimeZone(TimeZone.getTimeZone(ZoneId.of("Asia/Shanghai")));
        mapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
        // 循环引用处理
        mapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
        mapper.configure(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL, true);
        mapper.enable(SerializationFeature.USE_EQUALITY_FOR_OBJECT_ID);
        // 处理Hibernate延迟加载问题
        mapper.disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS);

        // 自定义模块
        SimpleModule module = new SimpleModule();
        module.addSerializer(Number.class, NumberSerializer.INSTANCE);

        module.addDeserializer(Object.class, NumberDeserializer.INSTANCE);
        module.addDeserializer(JsonNode.class, JSONNodeDeserializer.INSTANCE);
        module.addDeserializer(Long.class, LongDeserializer.INSTANCE);
        module.addDeserializer(Long.TYPE, LongDeserializer.INSTANCE);
        module.addDeserializer(long.class, LongDeserializer.INSTANCE);
        module.addDeserializer(Date.class, DateDeserializer.INSTANCE);
        module.addDeserializer(Boolean.class, BooleanDeserializer.INSTANCE);
        module.addDeserializer(Boolean.TYPE, BooleanDeserializer.INSTANCE);
        module.addDeserializer(boolean.class, BooleanDeserializer.INSTANCE);
        mapper.registerModule(module);
        mapper.registerModule(EnumModule.INSTANCE);
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        // 处理InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default问题
        mapper.registerModule(javaTimeModule);
        AutoDeserializeModule autoDeserializeModule = new AutoDeserializeModule("cn.dansj");
        mapper.registerModule(autoDeserializeModule);
        // 在解析完成后自动关闭输入源
        mapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
        //是否允许解析使用Java/C++ 样式的注释（包括'/'+'*' 和'//' 变量）
        mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        //是否以类名作为根元素，可以通过@JsonRootName来自定义根元素名称,默认false
        mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
        //序列化char[]时以json数组输出，默认false
        mapper.configure(SerializationFeature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS, true);
        // 设置自定义的 DeserializationProblemHandler
        mapper.addHandler(new DeserializationProblemHandler() {
            @Override
            public boolean handleUnknownProperty(DeserializationContext ctxt, JsonParser p, JsonDeserializer<?> deserializer, Object beanOrClass, String propertyName) throws IOException {
                // 跳过未知属性而不报错
                p.skipChildren();
                return true; // 表示已处理，不会抛出异常
            }

            @Override
            public Object handleWeirdStringValue(DeserializationContext ctxt, Class<?> targetType, String valueToConvert, String failureMsg) {
                // 处理无法转换的字符串值
                return null; // 返回null或默认值
            }

            @Override
            public Object handleWeirdNumberValue(DeserializationContext ctxt, Class<?> targetType, Number valueToConvert, String failureMsg) {
                // 处理无法转换的数字值
                return null; // 返回null或默认值
            }
        });

        mapper.setSerializerFactory(mapper.getSerializerFactory().withSerializerModifier(new BeanSerializerModifier() {
            @Override
            public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc, JsonSerializer<?> serializer) {
                // 创建一个类型安全的包装器
                return new JsonSerializer<Object>() {
                    @Override
                    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
                        try {
                            // 使用类型转换来调用原始序列化器
                            @SuppressWarnings("unchecked")
                            JsonSerializer<Object> typedSerializer = (JsonSerializer<Object>) serializer;
                            typedSerializer.serialize(value, gen, provider);
                        } catch (Exception e) {
                            // 处理错误，可以选择记录日志
                            gen.writeNull(); // 写入null或跳过该字段
                            logger.debug("{}@{}>>>序列化失败", value.getClass(), value);
                        }
                    }

                    @Override
                    public Class<Object> handledType() {
                        return Object.class;
                    }
                };
            }
        }));
    }

    private static synchronized void maybeCleanup() {
        long now = System.currentTimeMillis();
        if (now - lastCleanupTime > CLEANUP_INTERVAL) {
            cache.entrySet().removeIf(entry -> entry.getValue().get() == null);
            lastCleanupTime = now;
        }
    }

    public static JSONMapper getObjectMapperInstance(Feature... features) {
        if (features.length == 0) return mapper;
        maybeCleanup();
        EnumSet<Feature> enumSet = Feature.removeConflictingFeatures(Feature.featureEnumSet(features));
        return cache.compute(enumSet, (k, v) -> {
            if (v != null && v.get() != null) return v;
            JSONMapper mapper = createCopyObjectMapper(enumSet);
            return new WeakReference<>(mapper);
        }).get();
    }

    private static JSONMapper createCopyObjectMapper(EnumSet<Feature> enumSet) {
        JSONMapper copyMapper = mapper.copy();
        // 字段可见性配置
        if (enumSet.contains(Feature.FILED_BASE)) {
            copyMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
            copyMapper.configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, true);
        }
        // 日期格式配置
        if (enumSet.contains(Feature.USE_TIMESTAMPS)) {
            copyMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
            copyMapper.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, true);
        }
        //序列化枚举是否以toString()来输出，默认false，即默认以原型来输出
        if (enumSet.contains(Feature.ENUM_UPPERCASE_STRING)) {
            copyMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
        }
        // 枚举值小写
        if (enumSet.contains(Feature.ENUM_LOWERCASE_STRING)) {
            copyMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
            copyMapper.configure(EnumFeature.WRITE_ENUMS_TO_LOWERCASE, true);
        }
        //序列化枚举是否以ordinal()来输出，默认false
        if (enumSet.contains(Feature.ENUM_INDEX)) {
            copyMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX, true);
        }
        // 空值处理
        if (enumSet.contains(Feature.INCLUDE_NULL_FIELDS)) {
            copyMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        }
        if (enumSet.contains(Feature.NUMERIC_AS_STRING)) {
            copyMapper.configure(NumericFeature.USE_STRING_FOR_NUMERIC, true);
        }
        // 格式化打印
        if (enumSet.contains(Feature.PRETTY_PRINT)) {
            // 设置格式 缩进4个空格, 分隔符: , 右边一个空格，左边无空格
            DefaultPrettyPrinter.Indenter indenter = new DefaultIndenter("    ", DefaultIndenter.SYS_LF);
            Separators separators = Separators.createDefaultInstance().withArrayValueSpacing(Separators.Spacing.AFTER).withObjectEntrySpacing(Separators.Spacing.AFTER).withObjectFieldValueSpacing(Separators.Spacing.AFTER);
            DefaultPrettyPrinter printer = new DefaultPrettyPrinter(separators);
            printer.indentObjectsWith(indenter);
            printer.indentArraysWith(indenter);
            copyMapper.setDefaultPrettyPrinter(printer);
        }
        // 智能匹配key
        if (enumSet.contains(Feature.SMART_MATCH)) {
            // 自定义匹配驼峰格式
            // 注册智能字段匹配模块
            SimpleModule NameMappingModule = new SimpleModule();
            NameMappingModule.setDeserializerModifier(new BeanDeserializerModifier() {
                @Override
                public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
                    return new SmartFieldNameDeserializer(deserializer, beanDesc);
                }
            });
            copyMapper.registerModule(NameMappingModule);
        }
        // 处理gson注解
        if (hasGSONClass && enumSet.contains(Feature.SUPPORT_GSON_ANNOTATION)) {
            copyMapper.setAnnotationIntrospector(new GsonAnnotationIntrospector());
        }
        if (enumSet.contains(Feature.SUPPORT_NO_DEFAULT_CONSTRUCT)) {
            // 处理没有默认构造函数的问题
            copyMapper.setConstructorDetector(ConstructorDetector.USE_PROPERTIES_BASED);
            copyMapper.registerModule(new ParameterNamesModule());
        }
        if (enumSet.contains(Feature.ORDER_MAP_BY_KEYS)) {
            //序列化Map时对key进行排序操作，默认false
            copyMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
        }
        return copyMapper;
    }
}
